/**
 * #info
 *@author   lulg
 *@createTime   2018/03/20
 *@updateTime    2018/05/04
 *@description   splitable tabs  component 可分屏页签导航
 */

/**
 * #item
 *
 * @type        aty-splitable-tabs
 * @cn          页签导航
 * @menu        导航
 * @order   15
 * @stPlugin    true
 * @stContainer false
 * @children    aty-tabpane,aty-tabspace,template,aty-button,aty-link,aty-panel
 */

// 扩展属性
/**
 * #extendproperty
 *
 * @name    slot
 * @cn      额外内容
 * @type    list
 * @options [extra]
 * @value   extra
 * @description  aty-tabs插槽，<aty-button slot="extra">增加页签</aty-button>
 */
import config from '../../../config/config.js'

// components
import Icon from '../../basic/icon/index.vue'
import tab from '../../navigation/tabs/tab/tab.js'
import Emitter from '../../../mixins/emitter.js'
import elementResizeDetectorMaker from 'element-resize-detector'
//  prefix
const prefixCls = config.prefix + '-tabs'
// module
const module = {
  name: config.prefix + '-splitable-tabs',
  components: {
    Icon, tab
  },
  mixins: [Emitter],
  props: {
    /**
     * #property
     *
     * @name    splited
     * @cn      是否分屏
     * @type    boolean
     * @value   true
     * @bind   must
     * @description 是否分屏
     */
    splited: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    value
     * @cn      页签值
     * @type    array
     * @value   [0, 1]
     * @description 用于标识选中的页签，对应选中aty-tabpane的name值或index,可以使用v-model进行双向绑定
     */
    value: {
      type: Array,
      default () {
        return [0, 1]
      }
    },
    /**
     * #property
     *
     * @name    type
     * @cn      页签类型
     * @type    list
     * @options [line, card, trapezoid]
     * @value   line
     * @description 页签类型，line 线型， card 卡片型, trapezoid 梯形
     */
    type: {
      validator (value) {
        return Artery.isOneOf(value, ['line', 'card', 'trapezoid'])
      },
      default: 'line'
    },
    /**
     * #property
     *
     * @name    transformTime
     * @cn      页签类型
     * @type    list
     * @options [200, 300, 400, 500, 600]
     * @bind    must
     * @value   300
     * @description 切屏过度动画时间，单位毫秒
     */
    transformTime: {
      type: Number,
      default: 300
    },
    /**
     * #property
     *
     * @name    splitedInitStatus
     * @cn      分页默认状态
     * @type    list
     * @options [center, left-full, right-full]
     * @description 分页默认状态
     */
    splitedInitStatus: {
      validator (value) {
        return Artery.isOneOf(value, ['center', 'left-full', 'right-full'])
      }
    }
  },
  watch: {
    value (val) {
      this.activeKey = val
    },
    activeKey () {
      this.updateBar()
      this.updateStatus()
      // 折行代码不知道干嘛用，跟Table有交互
      this.broadcast('Table', 'on-visible-change', true)
      this.$nextTick(() => {
        this.scrollToActiveTab()
      })
    }
  },
  data () {
    return {
      prefixCls: prefixCls,
      navList: [],
      barWidth: 0,
      barHeight: 0,
      barOffset: 0,
      activeKey: this.value,
      showSlot: false,
      navStyle: {
        transform: ''
      },
      scrollable: false,
      scope: {
        className: config.prefix + '-tabs'
      },
      currentSrc: '',
      status: this.splitedInitStatus ? this.splitedInitStatus : (this.splited ? 'center' : 'left-full'),
      oldStatus: 'center',
      splitableLeft: true, // 左边可分屏
      splitableRight: true, // 右边可分屏,
      navsCount: 0,
      updated: false
    }
  },
  computed: {
    classes () {
      return [
                `${prefixCls}`,
                {
                  [`${prefixCls}-card`]: this.type === 'card',
                  [`${prefixCls}-trapezoid`]: this.type === 'trapezoid',
                },
                `${prefixCls}-no-animation`
      ]
    },
    contentClasses () {
      return [
                `${prefixCls}-content`,
                `${prefixCls}-top`
      ]
    },
    barContainnerClasses () {
      return [
                `${prefixCls}-bar`,
                `${prefixCls}-top`
      ]
    },
    barClasses () {
      return [
                `${prefixCls}-ink-bar`
      ]
    },
    contentStyle () {
      const x = this.navList.findIndex((nav) => nav.name === this.activeKey)
      const p = x === 0 ? '0%' : `-${x}00%`

      let style = {}
      if (x > -1) {
        style = {
          transform: `translateX(${p}) translateZ(0px)`
        }
      }
      return style
    },
    barStyle () {
      const style = {
        display: 'none'
      }
      if (this.type === 'card') {
        return style
      }
      if (this.type === 'line') {
        style.display = 'block'
      }

      style.left = `${this.barOffset}px`

      return style
    },
    leftSplitorClasses () { // 左箭头样式
      return ['splitor', 'arrow-left', this.status, 'splitor-' + this.transformTime]
    },
    leftSplitorShow () { // 左箭头可显示
      if (!this.splited) return false
      return (this.splitableRight && this.status === 'center') || (this.splitableLeft && this.status === 'left-full')
    },
    rightSplitorClasses () { // 右箭头样式
      return ['splitor', 'arrow-right', this.status, 'splitor-' + this.transformTime]
    },
    rightSplitorShow () { // 右箭头可显示
      if (!this.splited) return false
      return (this.splitableLeft && this.status === 'center') || (this.splitableRight && this.status === 'right-full')
    },
    leftSpan () {
      switch (this.status) {
        case 'center':
          return 12
        case 'left-full':
          return 24
        case 'right-full':
          return 0
      }
    }
  },
  methods: {
    filterTabs (children) {
      return children.filter(item => item.$options.name === config.prefix + '-tabs-tabpane' || item.$options.name === config.prefix + '-tabs-tabspace')
    },
    getTabs () {
      const all = this.filterTabs(this.$children)
      return all
    },
    updateNav () {
      let tabs = this.getTabs()
      if (this.navsCount === 0) {
        this.navsCount = tabs.length
      }
      if (this.navsCount !== tabs.length) {
        return
      }
      tabs = tabs.sort((a, b) => a.name > b.name ? 1 : -1)
      const tempNavList = tabs.map((pane, index) => {
        const item = {
          labelType: typeof pane.label,
          label: pane.label,
          icon: pane.icon || '',
          name: pane.name || index,
          disabled: pane.disabled,
          closable: pane.closable,
          index: index,
          labelVm: pane.$slots.label,
          isSpace: pane.isSpace,
          splitPosition: pane.splitPosition,
          splitable: pane.splitable
        }
        return item
      })
      this.navList = tempNavList
      this.updateStatus()
      this.updateBar()
    },
    updateBar () {
    },
    updateStatus () {
      const tabs = this.getTabs()
      tabs.forEach(tab => {
        let show = false
        if (Array.isArray(this.activeKey)) {
          show = this.activeKey.includes(tab.name)
        } else {
          show = tab.name === this.activeKey
        }
        tab.show = show
      })
    },
    tabCls (item) {
      const active = Array.isArray(this.activeKey) ? Array.includes(item.name) : item.name === this.activeKey

      return [
                `${prefixCls}-tab`,
                {
                  [`${prefixCls}-tab-disabled`]: item.disabled,
                  [`${prefixCls}-tab-active`]: active
                }
      ]
    },
    handleChange (index, name) {
      const nav = name ? this.navList.filter(n => n.name === name)[0] : this.navList[index]
      if (nav.disabled) return
      if (nav.splitPosition === 'left') {
        this.activeKey = [nav.name, this.activeKey[1]]
        this.splitableLeft = nav.splitable
      } else if (nav.splitPosition === 'right') {
        this.activeKey = [this.activeKey[0], nav.name]
        this.splitableRight = nav.splitable
      }
      this.$emit('input', this.activeKey)
      /**
       * #event
       *
       * @name    tabclick
       * @param   activeKey  当前激活的页签值
       * @param   value  当前选中的页签的name值
       * @description 页签的点击事件
       * @body
       */
      this.$emit('tabclick', this.activeKey, name)
    },
    handleRemove (index) {
      const tabs = this.getTabs()
      const tab = tabs[index]
      tab.$destroy()

      if (tab.name === this.activeKey) {
        const newTabs = this.getTabs()
        let activeKey = -1

        if (newTabs.length) {
          const leftNoDisabledTabs = tabs.filter((item, itemIndex) => !item.disabled && itemIndex < index)
          const rightNoDisabledTabs = tabs.filter((item, itemIndex) => !item.disabled && itemIndex > index)

          if (rightNoDisabledTabs.length) {
            activeKey = rightNoDisabledTabs[0].name
          } else if (leftNoDisabledTabs.length) {
            activeKey = leftNoDisabledTabs[leftNoDisabledTabs.length - 1].name
          } else {
            activeKey = newTabs[0].name
          }
        }
        this.activeKey = activeKey
        this.$emit('input', activeKey)
      }
      /**
       * #event
       *
       * @name    tabremove
       * @param   value  被删除的页签值
       * @body    if(value === 1) {this.showTab1 = false;}
       * @description  删除页签触发事件
       */
      this.$emit('tabremove', tab.name)
      this.updateNav()
    },
    showClose (item) {
      // if (this.type === 'card') {
      if (item.closable !== null) {
        return item.closable
      } else {
        return this.closable
      }
      /*
       * } else {
       * return false;
       *}
       */
    },
    scrollPrev () {
      const containerWidth = this.$refs.navScroll.offsetWidth
      const currentOffset = this.getCurrentScrollOffset()

      if (!currentOffset) return

      const newOffset = currentOffset > containerWidth
        ? currentOffset - containerWidth
        : 0

      this.setOffset(newOffset)
    },
    scrollNext () {
      const navWidth = this.$refs.nav.offsetWidth
      const containerWidth = this.$refs.navScroll.offsetWidth
      const currentOffset = this.getCurrentScrollOffset()
      if (navWidth - currentOffset <= containerWidth) return

      const newOffset = navWidth - currentOffset > containerWidth * 2
        ? currentOffset + containerWidth
        : (navWidth - containerWidth)

      this.setOffset(newOffset)
    },
    getCurrentScrollOffset () {
      const { navStyle } = this
      return navStyle.transform
        ? Number(navStyle.transform.match(/translateX\(-(\d+(\.\d+)*)px\)/)[1])
        : 0
    },
    setOffset (value) {
      this.navStyle.transform = `translateX(-${value}px)`
    },
    scrollToActiveTab () {
      if (!this.scrollable) return
      const nav = this.$refs.nav
      const activeTab = this.$el.querySelector(`.${prefixCls}-tab-active`)
      if (!activeTab) return

      const navScroll = this.$refs.navScroll
      const activeTabBounding = activeTab.getBoundingClientRect()
      const navScrollBounding = navScroll.getBoundingClientRect()
      const navBounding = nav.getBoundingClientRect()
      const currentOffset = this.getCurrentScrollOffset()
      let newOffset = currentOffset

      if (navBounding.right < navScrollBounding.right) {
        newOffset = nav.offsetWidth - navScrollBounding.width
      }

      if (activeTabBounding.left < navScrollBounding.left) {
        newOffset = currentOffset - (navScrollBounding.left - activeTabBounding.left)
      } else if (activeTabBounding.right > navScrollBounding.right) {
        newOffset = currentOffset + activeTabBounding.right - navScrollBounding.right
      }

      if (currentOffset !== newOffset) {
        this.setOffset(Math.max(newOffset, 0))
      }
    },
    isInsideHiddenElement () {
      let parentNode = this.$el.parentNode
      while (parentNode && parentNode !== document.body) {
        if (parentNode.style && parentNode.style.display === 'none') {
          return parentNode
        }
        parentNode = parentNode.parentNode
      }
      return false
    },
    calHeight () {
      return ''
    },
    getTabPart () {
      const tabsPrefix = config.prefix + '-tabs'
      return <div class={[`${tabsPrefix}-nav-container`]}>
        <div ref="nav" class={[`${tabsPrefix}-nav`, 'nav-text']} style={this.navStyle}>
          <tab position="top" activeKey={this.activeKey} navList={this.navList}
            on-tabchange={this.handleChange}
            onRemove={this.handleRemove}>
          </tab>
        </div>
      </div>
    },
    getContentPart (slotsVNode) {
      return <div class={this.contentClasses} style={[this.contentStyle, this.calHeight]}>
        {slotsVNode}
      </div>
    },
    handleLeftArrowClick () {
      this.oldStatus = this.status
      switch (this.status) {
        case 'left-full':
          this.status = 'center'
          break
        case 'center':
          this.status = 'right-full'
          break
      }
      this.$emit('status-change', this.status)
    },
    addClass (ele, cls) {
      if (!this.hasClass(ele, cls)) ele.className += ' ' + cls
    },
    hasClass (ele, cls) {
      return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
    },
    handleRightArrowClick () {
      let status = null
      switch (this.status) {
        case 'right-full':
          status = 'center'
          break
        case 'center':
          status = 'left-full'
          break
      }
      this.$emit('status-change', status)
      this.status = status
    },
    restore () {
      this.setStatus('center')
      this.$emit('status-change', this.status)
    },
    setStatus (status) {
      this.status = status
    }
  },
  updated () {
  },
  created () {
  },
  mounted () {
    this.showSlot = this.$slots.extra !== undefined
    this.observer = elementResizeDetectorMaker()
    /* this.observer.listenTo(this.$refs.nav, this.handleResize); */

    const hiddenParentNode = this.isInsideHiddenElement()
    if (hiddenParentNode) {
      this.mutationObserver = new Artery.MutationObserver(() => {
        if (hiddenParentNode.style.display !== 'none') {
          this.updateBar()
          this.mutationObserver.disconnect()
        }
      })
      this.mutationObserver.observe(hiddenParentNode, {
        attributes: true,
        childList: true,
        characterData: true,
        attributeFilter: ['style']
      })
    }
    if (this.shareframe) {
      this.getTabs().forEach((pane, index) => {
        if (this.activeKey === pane.name || this.activeKey === index) {
          this.currentSrc = pane.src
        }
      })
    }
  },
  beforeDestroy () {
    this.observer.removeListener(this.$refs.navWrap, this.handleResize)
    if (this.mutationObserver) this.mutationObserver.disconnect()
  },
  render (h) {
    const panels = this.$slots.default
    const leftPanes = panels.filter(v => {
      return v.componentOptions && v.componentOptions.propsData.splitPosition === 'left'
    })
    const rightPanes = panels.filter(v => {
      return v.componentOptions && v.componentOptions.propsData.splitPosition === 'right'
    })

    const leftContent = (<div class={this.contentClasses} style={[this.contentStyle, this.calHeight]}>
      {leftPanes}
    </div>)
    const rightContent = (<div class={this.contentClasses} style={[this.contentStyle, this.calHeight]}>
      {rightPanes}
    </div>)
    const tabPart = this.getTabPart()

    const rightSplitor = this.rightSplitorShow ? (
      <div class={this.rightSplitorClasses} on-click={this.handleRightArrowClick}>
      </div>) : (<template></template>)
    const leftSplitor = this.leftSplitorShow ? (
      <div class={this.leftSplitorClasses} on-click={this.handleLeftArrowClick}>
      </div>) : (<template></template>)

    const leftSpan = this.leftSpan
    const rightSpan = 24 - this.leftSpan
    const colClassesLeft = ['aty-col', 'col-left', 'aty-col-span-' + leftSpan, 'col-content']
    const colClassesRight = ['aty-col', 'col-right', 'aty-col-span-' + rightSpan, 'col-content']

    return <div class={this.classes}>
      {tabPart}
      <div class="aty-row row-content">
        {leftSplitor}
        {rightSplitor}
        <div class={colClassesLeft}>
          {leftContent}
        </div>
        <div class={colClassesRight}>
          {rightContent}
        </div>
      </div>
    </div>
  }
}
export default module
